package com.xinyue.server.framework.handler;

import com.xinyue.game.utils.encrypt.RSAUtils;
import com.xinyue.game.utils.encrypt.RsaKeyPair;
import com.xinyue.server.framework.common.GameServerUtil;
import io.netty.channel.Channel;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;

/**
 * 加解密管理，负责将加密的密钥与连接通道绑定
 *
 * @author 王广帅
 * @since 2021/11/13 22:46
 */
public class GameServerEncryptService {
    private static final Logger logger = LoggerFactory.getLogger(GameServerEncryptService.class);
    private static AttributeKey<byte[]> PUBLIC_KEY_KEY = AttributeKey.valueOf("publicKey_key");
    private static AttributeKey<byte[]> PRIVATE_KEY_KEY = AttributeKey.valueOf("privateKey_key");
    private static AttributeKey<byte[]> AES_KEY = AttributeKey.valueOf("aes_key");

    /**
     * 创建rsa算法的密钥对，并绑定到channel中
     *
     * @param channel
     * @return
     * @throws Exception
     */
    public static RsaKeyPair createAndBindRsaKeyPir(Channel channel) throws Exception {

        RsaKeyPair rsaKeyPair = RSAUtils.genKeyPair();
        Attribute<byte[]> attr = channel.attr(PUBLIC_KEY_KEY);
        attr.set(rsaKeyPair.getPublicKey());

        attr = channel.attr(PRIVATE_KEY_KEY);
        attr.set(rsaKeyPair.getPrivateKey());
        return rsaKeyPair;
    }

    /**
     * 获取某个channel已绑定的私钥
     *
     * @param channel
     * @return
     */
    public static byte[] getPrivateKey(Channel channel) {
        Attribute<byte[]> attr = channel.attr(PRIVATE_KEY_KEY);
        return attr.get();
    }

    /**
     * 绑定AES加密密钥
     *
     * @param channel
     * @param aesKey
     * @throws Exception
     */
    public static void bindAesKey(Channel channel, String aesKey) throws Exception {
        byte[] aesKeyBytes = Base64Utils.decodeFromString(aesKey);
        aesKeyBytes = RSAUtils.decryptByPrivateKey(aesKeyBytes, getPrivateKey(channel));
        Attribute<byte[]> attribute = channel.attr(AES_KEY);
        attribute.set(aesKeyBytes);
        logger.debug("绑定对称密钥成功，channelId:{},aesKey:{}", GameServerUtil.getChannelId(channel), aesKey);
    }

    /**
     * 获取当前连接通道的对称密钥
     *
     * @param channel
     * @return
     */
    public static byte[] getAesKey(Channel channel) {
        Attribute<byte[]> attribute = channel.attr(AES_KEY);
        return attribute.get();
    }
}
